home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime for java / createmovie / src / createmovie.java
Encoding:
Java Source  |  2000-09-28  |  9.4 KB  |  298 lines

  1. /*
  2.  * QuickTime for Java SDK Sample Code
  3.  
  4.    Usage subject to restrictions in SDK License Agreement
  5.  * Copyright: © 1996-1999 Apple Computer, Inc.
  6.  
  7.  */
  8.  
  9. import java.awt.*;
  10. import java.awt.event.*;
  11. import java.io.*;
  12.  
  13. import quicktime.qd.*;
  14. import quicktime.*;
  15. import quicktime.std.*;
  16. import quicktime.io.*;
  17. import quicktime.sound.*;
  18. import quicktime.std.image.*;
  19. import quicktime.std.movies.*;
  20. import quicktime.std.movies.media.*;
  21. import quicktime.util.*;
  22.  
  23. import createmovies.*;
  24.  
  25. import quicktime.app.display.*;
  26. import quicktime.app.image.*;
  27. import quicktime.app.QTFactory;
  28. /**
  29.  *     CreateMovie Demo.
  30.  */
  31.  
  32. public class CreateMovie extends Frame implements StdQTConstants, Errors {
  33.     static CreateMovie movieFrame;
  34.  
  35. //_________________________ CLASS METHODS
  36.     public static void main(String args[]) {
  37.         try {
  38.             QTSession.open();
  39.  
  40.             movieFrame = new CreateMovie("Movie Creation Demo using QuickTime and Java");
  41.             movieFrame.addWindowListener (new WindowAdapter () {
  42.                 public void windowOpened (WindowEvent we) {
  43.                     movieFrame.makeMovie();
  44.                 }
  45.                 public void windowClosing (WindowEvent e) {
  46.                     movieFrame.canv.removeClient();
  47.                     QTSession.close();
  48.                     movieFrame.dispose();
  49.                 }
  50.                 public void windowClosed (WindowEvent e) { 
  51.                     System.exit(0);
  52.                 }
  53.             });
  54.             movieFrame.show();
  55.             movieFrame.toFront();
  56.         } catch (Exception e) {
  57.             e.printStackTrace();
  58.             QTSession.close();
  59.         }
  60.     }
  61.  
  62.     public CreateMovie (String frameTitle) throws Exception {
  63.         super(frameTitle);
  64.         soundFile = QTFactory.findAbsolutePath ("sound.aif");
  65.  
  66.         canv = new QTCanvas (QTCanvas.kInitialSize, 0.5F, 0.5F);
  67.         add ("Center", canv);
  68.  
  69.         np = new NumberPainter(numFrames);
  70.         qid = new QTImageDrawer (np, new Dimension (kWidth, kHeight), Redrawable.kMultiFrame);
  71.         qid.setRedrawing(true);
  72.  
  73.         canv.setClient (qid, true);
  74.     
  75.         pack();
  76.     }        
  77.  
  78. //_________________________ INSTANCE VARIABLES
  79.     private QTCanvas canv;
  80.     private QTImageDrawer qid;
  81.     private NumberPainter np;
  82.     private static final int numFrames = 30;
  83.     private int kWidth = 330;
  84.     private int kHeight = 140;
  85.     private File soundFile;
  86.     
  87. //_________________________ INSTANCE METHODS
  88.     private void makeMovie() {
  89.         try {        
  90.             //
  91.             // show save-as dialog, create movie file & empty movie
  92.             //
  93.             FileDialog fd = new FileDialog (this, "Save Movie As...", FileDialog.SAVE);
  94.             fd.show();
  95.             if(fd.getFile() == null)
  96.                 throw new QTIOException (userCanceledErr, "");
  97.             QTFile f = new QTFile(fd.getDirectory() + fd.getFile());
  98.             Movie theMovie = Movie.createMovieFile (f,
  99.                                 kMoviePlayer, 
  100.                                 createMovieFileDeleteCurFile | createMovieFileDontCreateResFile);
  101.  
  102.             //
  103.             // add content
  104.             //
  105.             System.out.println ("Doing Video Track");
  106.             addVideoTrack( theMovie );
  107.             System.out.println ("Doing Audio Track");
  108.             addAudioTrack( theMovie );
  109.  
  110.             //
  111.             // save movie to file
  112.             //
  113.             OpenMovieFile outStream = OpenMovieFile.asWrite (f); 
  114.             theMovie.addResource( outStream, movieInDataForkResID, f.getName() );
  115.             outStream.close();
  116.             System.out.println ("Finished movie");
  117.         }
  118.         catch (Exception qte) {
  119.             qte.printStackTrace(); 
  120.         }
  121.     }
  122.     
  123.     private void addVideoTrack (Movie theMovie) throws QTException {
  124.         int kNoVolume    = 0;
  125.         int kVidTimeScale = 600;
  126.  
  127.         Track vidTrack = theMovie.addTrack (kWidth, kHeight, kNoVolume);
  128.         VideoMedia vidMedia = new VideoMedia (vidTrack, kVidTimeScale);  
  129.                                 
  130.         vidMedia.beginEdits();
  131.         addVideoSample (vidMedia);
  132.         vidMedia.endEdits();
  133.         
  134.         int kTrackStart    = 0;
  135.         int kMediaTime     = 0;
  136.         int kMediaRate    = 1;
  137.         vidTrack.insertMedia (kTrackStart, kMediaTime, vidMedia.getDuration(), kMediaRate);
  138.     }
  139.     
  140.     private void addVideoSample( VideoMedia vidMedia ) throws QTException {
  141.         QDRect rect = new QDRect (kWidth, kHeight);
  142.         QDGraphics gw = new QDGraphics (rect);
  143.         int size = QTImage.getMaxCompressionSize (gw, 
  144.                                                 rect, 
  145.                                                 gw.getPixMap().getPixelSize(),
  146.                                                 codecNormalQuality, 
  147.                                                 kAnimationCodecType, 
  148.                                                 CodecComponent.anyCodec);
  149.         QTHandle imageHandle = new QTHandle (size, true);
  150.         imageHandle.lock();
  151.         RawEncodedImage compressedImage = RawEncodedImage.fromQTHandle(imageHandle);
  152.         CSequence seq = new CSequence (gw,
  153.                                         rect, 
  154.                                         gw.getPixMap().getPixelSize(),
  155.                                         kAnimationCodecType, 
  156.                                         CodecComponent.bestFidelityCodec,
  157.                                         codecNormalQuality, 
  158.                                         codecNormalQuality, 
  159.                                         numFrames,    //1 key frame
  160.                                         null, //cTab,
  161.                                         0);
  162.         ImageDescription desc = seq.getDescription();
  163.  
  164.  //redraw first...
  165.            np.setCurrentFrame (1);
  166.         qid.redraw(null);
  167.  
  168.         qid.setGWorld (gw);
  169.         qid.setDisplayBounds (rect);
  170.             
  171.         for (int curSample = 1; curSample <= numFrames; curSample++) {
  172.                np.setCurrentFrame (curSample);
  173.             qid.redraw(null);
  174.             CompressedFrameInfo info = seq.compressFrame (gw, 
  175.                                                         rect, 
  176.                                                         codecFlagUpdatePrevious, 
  177.                                                         compressedImage);
  178.              boolean isKeyFrame = info.getSimilarity() == 0;
  179.              System.out.println ("f#:" + curSample + ",kf=" + isKeyFrame + ",sim=" + info.getSimilarity());
  180.              vidMedia.addSample (imageHandle, 
  181.                                     0, // dataOffset,
  182.                                     info.getDataSize(),
  183.                                     60, // frameDuration, 60/600 = 1/10 of a second, desired time per frame    
  184.                                     desc,
  185.                                     1, // one sample
  186.                                     (isKeyFrame ? 0 : mediaSampleNotSync)); // no flags
  187.        }
  188.         
  189.      //print out ImageDescription for the last video media data ->
  190.      //this has a sample count of 1 because we add each "frame" as an individual media sample
  191.          System.out.println (desc);
  192.  
  193.      //redraw after finishing...
  194.         qid.setGWorld (canv.getPort());
  195.            np.setCurrentFrame (numFrames);
  196.         qid.redraw(null);
  197.     }
  198.     
  199.     static class SoundData {
  200.         QTHandle sampleData;
  201.         SoundDescription description;
  202.         int numSamples;
  203.     }
  204.     
  205.     private void addAudioTrack (Movie theMovie) throws QTException, IOException {
  206.         int kFullVolume    = 1;
  207.             
  208.             // fills in the above SoundData class fields
  209.         SoundData theSound = getSound();
  210.     
  211.             //print out the SoundDescription
  212.         System.out.println (theSound.description);
  213.             
  214.             //create Sound track with SoundMedia object -> the rounded sample rate is the time scale of the sound media
  215.         Track sndTrack = theMovie.addTrack (0, 0, kFullVolume);
  216.         SoundMedia sndMedia = new SoundMedia (sndTrack, theSound.description.getSampleRateRounded());  
  217.  
  218.             //add the sample data into the sound media
  219.         sndMedia.beginEdits();
  220.         sndMedia.addSample (theSound.sampleData,
  221.                                 0,
  222.                                 theSound.sampleData.getSize(),
  223.                                 1, // duration of each sound sample,
  224.                                 theSound.description,
  225.                                 theSound.numSamples,
  226.                                 0);
  227.         sndMedia.endEdits();
  228.             
  229.             // insert the media into the track
  230.         int kTrackStart    = 0;
  231.         int kMediaTime     = 0;
  232.         int kMediaRate    = 1;
  233.         sndTrack.insertMedia (kTrackStart, kMediaTime, sndMedia.getDuration(), kMediaRate);
  234.     }
  235.     
  236.     private SoundData getSound() throws QTException, IOException {        
  237.         //
  238.         // read sound.aif file into memory and create a description and read the sound data out of it.
  239.         //
  240.                                                 
  241.         SndInfo info = SndInfo.parseAIFFHeader (OpenFile.asRead (new QTFile(soundFile)));
  242.         
  243.         SoundData sd = new SoundData();
  244.  
  245.         SoundComponentData mySndInfo = info.sndData;
  246.  
  247.         sd.description = new SoundDescription (mySndInfo.getFormat());
  248.         sd.description.setNumberOfChannels (mySndInfo.getNumChannels());
  249.         sd.description.setSampleSize (mySndInfo.getSampleSize());
  250.         sd.description.setSampleRate (mySndInfo.getSampleRate());
  251.         
  252.         int mySampleDataSize = mySndInfo.getSampleCount() * (mySndInfo.getSampleSize() / 8); 
  253.             //read just the sample data into memory
  254.             // it is sample data size and is found at the data offset location in the file
  255.             // as returned by the ParseAIFF header call
  256.             FileInputStream fis = new FileInputStream (soundFile);
  257.             byte[] ar = new byte [mySampleDataSize];            
  258.             fis.skip (info.dataOffset);
  259.             fis.read (ar, 0, mySampleDataSize);
  260.         
  261.         sd.sampleData = new QTHandle (ar);
  262.         
  263.         sd.numSamples = mySndInfo.getSampleCount();
  264.         return sd;
  265.     }
  266. }
  267.  
  268.  
  269. /* THIS way captures the result of the draw method of the QTImageDrawer
  270.     it then adds the raw pixel data to the movie, getting that raw data and description
  271.     from the ImagePresenter of the QTImageDrawer
  272.     
  273.     the way we add data above is to compress the GWorld the QTImageDrawer draws to
  274.     using the animation compressor -> which also gives us frame differencing and a smalller data size
  275.     and better playback for the movie.
  276.     
  277.     this code is presented as an alternative which may be appropriate in certain instances
  278.     -> like adding image data for a sprite where no fidelity on each image is lost.
  279.     in this case the important point is NOT the QTImageDrawer but the addition
  280.     of the raw EncodedImage and ImageDescription -> how we get that is up to the application.
  281.     
  282.         for (int curSample = 1; curSample <= numFrames; curSample++) {
  283.                QTUtils.reclaimMemory();
  284.                np.setCurrentFrame (curSample);
  285.             qid.redraw(null);
  286.             ImagePresenter ip = qid.toImagePresenter();
  287.             ImageDescription desc = ip.getDescription();
  288.             EncodedImage imageData = ip.getImage(1);            
  289.             vidMedia.addSample (QTHandle.fromEncodedImage(imageData), 
  290.                                     0, // dataOffset,
  291.                                     desc.getDataSize(),
  292.                                     60, // frameDuration, 60/600 = 1/10 of a second, desired time per frame    
  293.                                     desc,
  294.                                     1, // one sample
  295.                                     0 ); // no flags
  296.         }
  297. */                
  298.